Skip to content

feat(design): add cookie consent and footer - #509

Open
uniqueg wants to merge 6 commits into
devfrom
feat/compliance
Open

uniqueg wants to merge 6 commits into
devfrom
feat/compliance

Conversation

@uniqueg

@uniqueg uniqueg commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Description

Apps built on the components (first the Cloud Registry UI, elixir-cloud-aai/cloud-registry-ui#38) need cookie consent and links to legal information that operators configure per deployment, without code changes. This adds two components to @elixir-cloud/design that read one shared configuration (ComplianceConfig, e.g. from a JSON setting):

  • ecc-utils-design-cookie-consent (config.cookies): a banner on the first visit with equally prominent "Accept all", "Necessary only" and "Customize"; a preferences dialog per category (native <dialog>); consent stored in localStorage and asked again when the categories (IDs, required) or version change. Without optional categories no banner is shown, unless notice is set. Fires ecc-cookie-consent-changed (on the element, not bubbling, and on window).
  • ecc-utils-design-compliance-footer (config.footer): default items (Privacy Policy, Terms & Conditions, Cookie Policy, Cookie Preferences, Imprint, Accessibility Statement, Contact Us, Your Privacy Choices) that operators give an action, rename, hide or extend. Actions: link, mailto, preferences, page (Markdown subset, rendered with Lit, so all text is escaped) and embed (an https page in a sandboxed frame, e.g. from Iubenda, Termly or GetTerms; with consent, only after consent to that category). Fires the cancelable ecc-compliance-item-selected, so apps can route items themselves.
  • Functions for other code (components/cookie-consent/index.js, also from the main entry): hasConsent(), readConsent(), saveConsent(), onConsentChange() (also reports changes from other tabs), openCookiePreferences(), footerItems().
  • Safety: configured URLs are checked (http(s), mailto and relative links only, no javascript:/data:; embeds only https, or http on localhost; mailto only plain addresses). Same-origin embeds get no allow-same-origin, so they can't lift their sandbox. Consent that can't be stored applies to the page only and never falls back to an older stored choice.
  • Docs: pages for both components with live previews, usage (Lit and React), configuration, operator notes (GDPR/ePrivacy basics, CSP frame-src for embeds, embeds that set cookies).
  • Tests: 47 cases (store, edge cases such as a required category becoming optional, full storage, other tabs, URL checks, Markdown, both components). Adds the package's test script (--port 8003) and the tsconfig option of the shared test config, as fix(cloud-registry): react to provider changes #502, feat(cloud-registry): expose problem details #504 and feat: add surface, font and dark mode controls #446 do.

No existing API changes; the components and types are new.

Closes #458

How it was verified

  • npm run lint (husky, whole repo): 0 errors, warnings unchanged.
  • npx turbo run build --filter=@elixir-cloud/design and --filter=ecc-docs: pass (React wrappers generated).
  • npx web-test-runner --group default in packages/ecc-utils-design with Chromium and Firefox: 47/47 pass. WebKit can't start on my machine; CI runs it.
  • Browser check of the built docs site with Playwright in Chromium and Firefox (script kept outside the repo): banner on the first visit, "Necessary only" stores no optional consent, no banner after reload, "Cookie Preferences" in the footer reopens and saves the preferences, Markdown page dialog, mailto and external links, no page errors.
  • CI: all checks pass at 0440672 (lint, tests on Node 22 and 24 in Chromium, Firefox and WebKit, docs build, Sourcery). The nine Sourcery threads were fixed (eight) or answered (the docs version), and resolved.

Checklist

  • My code follows the contributing guidelines of this project.
  • I am aware that all my commits will be squashed into a single commit, using the PR title as the commit message.
  • I have performed a self-review of my own code.
  • I have commented my code in hard-to-understand areas.
  • I have updated the user-facing documentation to describe any new or changed behavior.
  • My changes generate no new warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have not reduced the existing code coverage.

Comments

  • Package: the components live in @elixir-cloud/design rather than a new package, because a new npm package needs its own trusted-publishing and release setup. Happy to move them into a separate package (e.g. @elixir-cloud/compliance) if you prefer.
  • Script embeds (a <script> that injects a policy) aren't supported, since configuration must not run code on the page; most policy services also offer a page URL to embed or link.
  • Test ports: cloud-registry uses 8002 (fix(cloud-registry): react to provider changes #502, feat(cloud-registry): expose problem details #504), design 8003 here, wes the default 8000. feat: add surface, font and dark mode controls #446 plans design 8000 / wes 8001; whichever lands second adjusts.
  • ecc-cookie-consent-changed is written as a literal in new CustomEvent(...), not via the exported constant, because the React wrapper generator reads the event name from that call.

Declined review findings

  • Moving the shared code (consent.ts, urls.ts) from components/cookie-consent/ to a neutral folder: the footer imports it from there; the package has no shared folder for non-component code yet, and the cookie consent is its natural owner.
  • Markdown subset instead of a Markdown library: keeps the package free of new dependencies and makes escaping easy to verify; the subset covers typical legal pages.

🤖 Generated with Claude Code

Summary by Sourcery

Add configurable cookie consent and compliance footer components to provide deployment-specific privacy controls and legal information without application code changes.

New Features:

  • Add configurable cookie consent and preferences UI with category-based choices, persistent storage, versioning, cross-tab updates, and consent change events.
  • Add a configurable compliance footer with legal links, email actions, cookie preferences, Markdown pages, consent-gated embeds, and app-controlled selection events.
  • Expose shared compliance types and consent utilities for integrating optional functionality with user consent.

Enhancements:

  • Validate configured links, email addresses, embeds, and Markdown content to prevent unsafe navigation or script execution.
  • Support deployment-specific labels, texts, defaults, hidden or custom footer items, and consent-gated embedded content.

Documentation:

  • Document both components with live previews, framework usage, configuration guidance, security considerations, and operator compliance notes.

Tests:

  • Add comprehensive coverage for consent storage, configuration changes, cross-tab behavior, URL validation, Markdown rendering, and both compliance components.

uniqueg and others added 3 commits October 29, 2026 00:26
Add two components with a shared configuration (ComplianceConfig), so
that apps add cookie consent and a compliance footer from
configuration alone:

- ecc-utils-design-cookie-consent: banner on the first visit (accept
  all, necessary only, customize), preferences dialog per category,
  consent in localStorage, asked again when the categories or the
  version change; hasConsent(), onConsentChange(),
  openCookiePreferences() and a window event for other code.
- ecc-utils-design-compliance-footer: default legal items (privacy,
  terms, cookie policy, cookie preferences, imprint, accessibility,
  contact, privacy choices) that operators change, hide or extend;
  actions link, mailto, preferences, Markdown page (escaped subset)
  and https embed (sandboxed, optionally gated by consent).

Configured URLs are checked (no javascript: links). Docs pages with
previews and operator notes; tests for both components.

Closes #458

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review fixes for the compliance components:

- Consent signature includes whether a category is required, so a
  category that becomes optional asks users again.
- Consent that can't be written takes precedence over an older stored
  choice, which is removed, so revoking works with full storage.
- onConsentChange() takes the config and also reports changes from
  other tabs (storage events); both components follow them.
- The cookie consent keeps unsaved choices when an equal config object
  is passed (e.g. on every React render).
- mailto items accept only plain addresses (no percent-encoding).
- Same-origin embeds get no allow-same-origin in their sandbox.
- Markdown links open a new tab only for other origins.
- Footer dialog texts (texts.close); listeners removed on disconnect;
  URL tests; docs on consent-less embeds and Cookie Preferences.

Refs #458

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A storage event drops consent kept in memory after a failed write,
  since the other tab's write is newer; a cleared storage (key null)
  counts too.
- The cookie consent refreshes when its preferences close and when it
  is connected again, so changes made meanwhile aren't missed.

Refs #458

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Data structures

Define the shared consent, category, footer-item, and configuration data structures that underpin both components and their public utilities.

  • packages/ecc-utils-design/src/components/cookie-consent/consent.ts L1-130

API

Expose the consent and footer component entry points, shared utilities, and typed component events to package consumers.

  • packages/ecc-utils-design/src/components/compliance-footer/index.ts L1-22
  • packages/ecc-utils-design/src/components/cookie-consent/index.ts L1-24
  • packages/ecc-utils-design/src/components/index.ts L17-19
  • packages/ecc-utils-design/src/events/ecc-compliance-item-selected.ts L1-12
  • packages/ecc-utils-design/src/events/ecc-cookie-consent-changed.ts L1-12
  • packages/ecc-utils-design/src/events/index.ts L7-8

Implementation

Implement consent persistence, validation, cross-tab notifications, and footer-item merging used by the public components and helper functions.

  • packages/ecc-utils-design/src/components/cookie-consent/consent.ts L131-440

Implement URL validation for links, embeds, external-origin checks, and mailto actions used by both components.

  • packages/ecc-utils-design/src/components/cookie-consent/urls.ts L1-98

Render the supported Markdown subset as escaped Lit templates for legal pages in the footer dialog.

  • packages/ecc-utils-design/src/components/compliance-footer/markdown.ts L1-132

UI

Provide the cookie banner and preferences dialog, including saving choices, following consent updates, and opening preferences on request.

  • packages/ecc-utils-design/src/components/cookie-consent/cookie-consent.ts L1-318

Provide the configurable legal footer, its actions and dialog, consent-gated embeds, and item-selection event.

  • packages/ecc-utils-design/src/components/compliance-footer/compliance-footer.ts L1-246

Documentation

Document footer configuration, supported actions, safety constraints, and examples for React and HTML consumers.

  • apps/documentation/pages/docs/design/components/compliance-footer.mdx L1-130

Document cookie-consent behavior, configuration, integration examples, and operator guidance for loading optional scripts only with consent.

  • apps/documentation/pages/docs/design/components/cookie-consent.mdx L1-179

Register the new component documentation pages in the design components navigation.

  • apps/documentation/pages/docs/design/components/_meta.json L18-20

Tests

Test footer item merging, Markdown safety, footer actions, dialogs, consent-gated embeds, and listener cleanup.

  • packages/ecc-utils-design/src/components/compliance-footer/tests/compliance-footer.test.ts L1-337

Test consent storage, signatures, category edge cases, cross-tab updates, component behavior, and URL safety.

  • packages/ecc-utils-design/src/components/cookie-consent/tests/cookie-consent.test.ts L1-576
  • packages/ecc-utils-design/src/components/cookie-consent/tests/urls.test.ts L1-59

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@uniqueg
uniqueg requested a review from anuragxxd October 29, 2026 01:13
@uniqueg
uniqueg marked this pull request as ready for review October 29, 2026 01:13

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 9 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/ecc-utils-design/src/components/compliance-footer/compliance-footer.ts" line_range="178" />
<code_context>
+    // a same-origin frame with both flags could lift its own sandbox
+    const sandbox = isSameOrigin(src)
+      ? "allow-scripts allow-popups allow-popups-to-escape-sandbox"
+      : "allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox";
+    return html`<iframe
+      class="mt-4 h-[60vh] w-full rounded-md border border-border"
</code_context>
<issue_to_address>
**Embedded content escapes sandbox restrictions**

When a visitor interacts with a malicious or compromised external embed, the external-frame sandbox allows popups to escape sandboxing. A malicious or compromised embed can open an unsandboxed popup after a user interaction and use it to navigate the app's top-level window, bypassing the frame's sandbox restrictions.

Omit `allow-popups-to-escape-sandbox` or disallow popups for embedded content.
</issue_to_address>

### Comment 2
<location path="packages/ecc-utils-design/src/components/cookie-consent/consent.ts" line_range="342-343" />
<code_context>
+  config?: CookieConsentConfig
+): () => void {
+  const handler = (event: Event) => {
+    const { detail } = event as CustomEvent<{ consent: CookieConsent }>;
+    if (detail?.consent) listener(detail.consent);
+  };
+  const storageHandler = (event: StorageEvent) => {
</code_context>
<issue_to_address>
**Other configurations receive consent**

When multiple consent configurations with different storage keys are used on the same page and one saves consent, `onConsentChange`'s same-window handler forwards every `CONSENT_CHANGED_EVENT` payload without matching the subscribed config's storage key or signature, so listeners receive unrelated choices and can enable optional behavior without consent for their configuration.

Match each event's consent to the subscribed configuration's storage key or signature before invoking its listener.
</issue_to_address>

### Comment 3
<location path="packages/ecc-utils-design/src/components/cookie-consent/cookie-consent.ts" line_range="108" />
<code_context>
+  private listen(): void {
+    this.stopListening?.();
+    this.stopListening = onConsentChange(() => {
+      if (!this.dialog?.open) this.refresh();
+    }, this.config?.cookies);
+  }
</code_context>
<issue_to_address>
**Stale preferences overwrite newer consent**

When one tab changes consent while another tab's preferences dialog is open, and the second tab then saves, `listen()` skips `refresh()` while the dialog is open, so this tab's `choices` remain stale; saving them calls `saveConsent()` for every category and overwrites the other tab's newer choices.

Reconcile incoming consent with the dialog's edits before saving, or detect that consent changed since the dialog opened and refresh or ask the user to resolve it.
</issue_to_address>

### Comment 4
<location path="packages/ecc-utils-design/src/components/cookie-consent/consent.ts" line_range="323-324" />
<code_context>
+    updatedAt: new Date().toISOString(),
+  };
+  writeItem(consentStorageKey(config), JSON.stringify(consent));
+  window.dispatchEvent(
+    new CustomEvent(CONSENT_CHANGED_EVENT, { detail: { consent } })
+  );
+  return consent;
</code_context>
<issue_to_address>
**Reentrant saves deliver stale consent**

When an earlier consent-change listener saves consent while handling an event, and a later listener also reacts to consent changes, `dispatchEvent()` invokes listeners synchronously, so an earlier listener that calls `saveConsent()` dispatches a newer event before the outer dispatch reaches later listeners; those listeners then receive the newer consent followed by the stale one and can re-enable behavior after a revocation.

Queue consent notifications and drain them in save order rather than allowing nested dispatches to overtake the outer event.
</issue_to_address>

### Comment 5
<location path="packages/ecc-utils-design/src/components/cookie-consent/consent.ts" line_range="314" />
<code_context>
+  }
+  const categories: Record<string, boolean> = {};
+  cookieCategories(config).forEach((category) => {
+    categories[category.id] =
+      !!category.required || consent.categories?.[category.id] === true;
+  });
</code_context>
<issue_to_address>
**The special category choice is lost**

When a configured category has the ID `__proto__`, `saveConsent()` assigns the category into ordinary objects, so the inherited `__proto__` setter prevents the choice from being stored or serialized; reads then miss the consent and the preference can appear enabled regardless of the user's choice.

Use prototype-safe records or equivalent own-property handling for category choices and saved consent.

Also at `packages/ecc-utils-design/src/components/cookie-consent/cookie-consent.ts:138-139`, `packages/ecc-utils-design/src/components/cookie-consent/consent.ts:273-276`.
</issue_to_address>

### Comment 6
<location path="packages/ecc-utils-design/src/components/cookie-consent/consent.ts" line_range="190" />
<code_context>
+ * @param config Cookie consent configuration
+ * @returns The categories
+ */
+export function cookieCategories(
+  config?: CookieConsentConfig
+): CookieCategory[] {
</code_context>
<issue_to_address>
**Duplicate categories conflict**

When configured categories contain duplicate IDs with conflicting `required` values, including a non-required `necessary` category when the default is added, `cookieCategories()` retains duplicate IDs, so the preferences can show conflicting switches while `saveConsent()` stores one value per ID and `hasConsent()` can treat the category as granted even after rejection.

Deduplicate category IDs while preserving the required category's consent semantics.

Also at `packages/ecc-utils-design/src/components/cookie-consent/consent.ts:193-198`, `packages/ecc-utils-design/src/components/cookie-consent/consent.ts:292-298`, `packages/ecc-utils-design/src/components/cookie-consent/consent.ts:314-315`.
</issue_to_address>

### Comment 7
<location path="packages/ecc-utils-design/src/components/cookie-consent/consent.ts" line_range="193" />
<code_context>
+export function cookieCategories(
+  config?: CookieConsentConfig
+): CookieCategory[] {
+  const categories = (config?.categories ?? []).filter(
+    (category) => category && typeof category.id === "string" && category.id
+  );
</code_context>
<issue_to_address>
**Malformed config breaks rendering**

When runtime deployment configuration supplies a non-array `cookies.categories` or `footer.items` value, `cookieCategories` or `footerItems` calls `.filter()` on the configured value, so a deployment setting with `categories` or `items` set to a non-array throws during component updates and the consent or footer UI fails to render. No runtime shape check catches this.

Validate these fields as arrays before filtering and fall back safely or report the invalid setting.

Also at `packages/ecc-utils-design/src/components/cookie-consent/consent.ts:374`.
</issue_to_address>

### Comment 8
<location path="packages/ecc-utils-design/src/components/cookie-consent/cookie-consent.ts" line_range="124" />
<code_context>
+  private async openDialog(item: DialogItem): Promise<void> {
+    this.openItem = item;
+    await this.updateComplete;
+    if (this.dialog && !this.dialog.open) this.dialog.showModal();
+  }
+
</code_context>
<issue_to_address>
**Detached dialogs reject opening**

When the component is removed after an open request schedules an update but before `updateComplete` resolves, `showModal()` runs after an `await` without checking whether the component is still connected; removing the component while its update is pending leaves the dialog detached, so `showModal()` throws and the preferences or footer page does not open.

After awaiting `updateComplete`, return without opening the dialog if the component is no longer connected.

Also at `packages/ecc-utils-design/src/components/compliance-footer/compliance-footer.ts:107`.
</issue_to_address>

### Comment 9
<location path="apps/documentation/pages/docs/design/components/cookie-consent.mdx" line_range="99" />
<code_context>
+  </Tabs.Tab>
+  <Tabs.Tab>
+    ```html showLineNumbers copy filename="index.html"
+    <script type="module" src="https://esm.sh/@elixir-cloud/design@2.0.0-alpha.50/components/cookie-consent"></script>
+    <ecc-utils-design-cookie-consent></ecc-utils-design-cookie-consent>
+    <script type="module">
</code_context>
<issue_to_address>
**HTML examples load unavailable release**

The package version is `2.0.0-alpha.49`, so these URLs request `2.0.0-alpha.50`, which is not the version built by this PR. Users following either HTML example fail to load the component or load no implementation of the new feature.

Point the examples at the package version that contains these components, or bump the package version to `2.0.0-alpha.50` through the release process.

Also at `apps/documentation/pages/docs/design/components/compliance-footer.mdx:70`.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 9 findings to address first, and if consent checks or their configuration are wrong, an optional embed or script could load before the user has agreed, sending browsing data to a third party. Reverting can stop future loads, but it cannot undo data already disclosed.

Blocking findings: packages/ecc-utils-design/src/components/compliance-footer/compliance-footer.ts:178, packages/ecc-utils-design/src/components/cookie-consent/consent.ts:343, packages/ecc-utils-design/src/components/cookie-consent/cookie-consent.ts:108, packages/ecc-utils-design/src/components/cookie-consent/consent.ts:324, packages/ecc-utils-design/src/components/cookie-consent/consent.ts:314, and 4 more


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

uniqueg and others added 2 commits October 29, 2026 02:37
Fixes from the automated review:

- onConsentChange() reports only consent of its config's storage key;
  the window event's detail carries the storage key.
- Consent events are dispatched in save order, also when a listener
  saves consent itself.
- Categories with the same ID are merged (required wins); __proto__ and
  non-array settings are skipped, also for footer items.
- Consent from another tab is merged into open preferences: categories
  the user switched stay, the others follow.
- Dialogs don't open once the element was removed.
- Embeds lose allow-popups-to-escape-sandbox.

Refs #458

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve the conflict in the design package's test scripts: take
dev's port 8000, as assigned to the package in #446.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linked issues

#458 feat: cookie consent and compliance footer · 9 of 10 met

# Requirement Status Notes
1 Show a consent banner on the first visit 🟡 Partly met The banner is suppressed when there are no optional categories unless notice is enabled.
2 Collect consent per category, including necessary and configurable categories ✅ Met Categories are configurable, and a required necessary category is added when none is marked required.
3 Store consent in the browser and ask again when configured categories change ✅ Met Consent is stored in localStorage, and the signature includes category IDs, required status, and policy version.
4 Provide a way to reopen cookie preferences ✅ Met The footer preferences action and openCookiePreferences() open the preferences dialog.
5 Provide an API or event for checking consent before loading optional scripts ✅ Met The change exports hasConsent(), onConsentChange(), and consent events.
6 Provide a configurable compliance footer with the listed default items ✅ Met The defaults are defined in the shared consent module; entries without actions are not displayed.
7 Let operators remove, change, and add footer items ✅ Met Footer configuration supports overrides, hidden items, additional items, and replacing the defaults.
8 Support Markdown pages, embeds, mailto, preferences, and external links as item actions ✅ Met Each action is supported; embed actions can name a consent category and wait for that consent before rendering the frame.
9 Document a sample configuration and what operators must provide ✅ Met The component docs include configuration examples and operator notes on policies, consent, and embed CSP.
10 Allow apps to add consent management and a footer from configuration alone ✅ Met Both components consume the shared ComplianceConfig.

@codecov

codecov Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.50000% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.79%. Comparing base (4655158) to head (c79f40e).

Files with missing lines Patch % Lines
...utils-design/src/components/cookie-consent/urls.ts 86.73% 12 Missing and 1 partial ⚠️
...ls-design/src/components/cookie-consent/consent.ts 98.18% 7 Missing and 1 partial ⚠️
...esign/src/components/compliance-footer/markdown.ts 94.69% 6 Missing and 1 partial ⚠️
.../components/compliance-footer/compliance-footer.ts 98.37% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #509      +/-   ##
==========================================
+ Coverage   73.53%   76.79%   +3.26%     
==========================================
  Files          33       40       +7     
  Lines        8123     9403    +1280     
  Branches      381      542     +161     
==========================================
+ Hits         5973     7221    +1248     
- Misses       2141     2169      +28     
- Partials        9       13       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@uniqueg uniqueg mentioned this pull request Nov 1, 2026
3 tasks
@sourcery-ai

sourcery-ai Bot commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

Linked issues

Checked at commit c79f40e

#458 feat: cookie consent and compliance footer · 7 of 7 met

# Requirement Status Notes
1 Provide cookie consent and a compliance footer using a shared configuration. ✅ Met Both components use ComplianceConfig and are exposed as custom elements, with React usage documented.
2 Show a first-visit consent banner with choices per category, store consent in the browser, and ask again when configured categories change. ✅ Met The banner and preferences use the configured categories; consent is stored in localStorage and its signature includes category IDs, required status, and policy version.
3 Let users reopen preferences and let other code check consent before loading optional scripts. ✅ Met The component, footer preferences action, and openCookiePreferences() reopen preferences; hasConsent(), readConsent(), saveConsent(), and onConsentChange() expose consent to other code.
4 Provide the listed default footer items and let operators remove, change, and add items. ✅ Met The defaults are defined in DEFAULT_FOOTER_ITEMS; configuration supports overrides, hidden items, additions, and replacing the defaults.
5 Support footer actions for static pages, embeds, mailto, cookie preferences, and links. ✅ Met The footer implements all five action types; embeds can be gated on a configured consent category.
6 Document a sample configuration and what operators must provide. ✅ Met The new component docs include usage examples, configuration tables, and operator notes on policies, consent categories, and embeds.
7 Allow apps to add consent management and a compliance footer from configuration alone, without operator-specific code changes. ✅ Met The components share deployment configuration, with setup examples showing configuration supplied by runtime settings.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: cookie consent and compliance footer

1 participant